const gulp = require('gulp'); // gulp

const fs = require('fs'); // 文件系统
const os = require('os'); // 操作系统信息，获取本机的局域网IP
const path = require('path'); // 路径模块

const del = require('del'); // 删除文件/文件夹
const yaml = require('js-yaml'); // YAML 工具

const $ = require('gulp-load-plugins')(); // gulp 插件加载工具，自动加载 package.json 里的 gulp 插件

const buildConfig = require('./build/config.js');

var argv = require('yargs').argv; // 提取控制台变量

var distFolder = argv.dist || 'dist';

// 输出目录
function getDistFolder(distPath) {
  return `${distFolder}/${distPath}`;
}

// 获取本机在局域网内的 ip 地址（windows 系统）
const getLocalIp = (token = '192') => {

  if (argv.local) {
    return 'localhost';
  }

  var nifs = os.networkInterfaces(); // 获取网卡信息
  for (var cur in nifs) {
    var _ns = nifs[cur] || [];
    for (let i = 0; i < _ns.length; i++) {
      let item = _ns[i];
      if (item.family === 'IPv4' && item.address.indexOf(token) === 0) {
        return item.address;
      }
    }
  }
  return '';
};

// JS 压缩的参数
const uglifyOptions = {
  preserveComments: 'license'
};

// 控制台输出字符串，这里使用粉红色
const log = (str) => {
  $.util.log($.util.colors.magenta(str));
};

// 空操作
const noop = $.util.noop;

// 读取 yml 文件内容
function loadYML(ymlFilePath) {
  return yaml.safeLoad(fs.readFileSync(ymlFilePath, 'utf8'));
}

gulp.task('config', () => {
  const config = loadYML('_config.yml');
  const ip = getLocalIp(config.local.token) || config.local.ip;

  buildConfig(distFolder, ip, config, argv, log);
});

// 监视 config 改动
gulp.task('watch:config', () => {
  gulp.watch('_config.yml', ['config']);
});

// 运行服务器
gulp.task('server', ['icon'], () => {
  var config = loadYML('_config.yml');
  var ip = getLocalIp(config.local.token);
  var serverOptions = {};
  serverOptions.host = ip || config.local.ip;
  serverOptions.port = config.local.port;
  if (argv.live || argv.livereload) {
    serverOptions.livereload = true;
  }
  if (argv.list || argv.directory) {
    serverOptions.directoryListing = true;
  }
  if (argv.open !== false && argv.open !== 0 && argv.open !== 'false') { // 强制指定 open 为 0 或 false 时不打开页面
    serverOptions.open = `http://${ip || config.local.accessIp || config.local.ip}:${config.local.port}/${typeof argv.open === 'string' ? argv.open : 'index'}.html`;
  }
  return gulp.src(distFolder)
    .pipe($.webserver(serverOptions));
});

// 清理文件！
gulp.task('clean', () => {
  if (/src|node|bower/i.test(distFolder)) {
    log('禁止清理：' + distFolder);
  } else {
    del(distFolder + '/**/*').then(() => {
      log('完成清理：' + distFolder);
    });
  }
});

// 定义源文件相关路径
const src = {
  less: {
    bootstrap: ['src/less/bootstrap/bootstrap.less'],
    bootstrapWatch: ['src/less/bootstrap/**/*.less'],
    common: ['src/less/common/common.less'],
    commonBase: 'src/less/common',
    commonWatch: ['src/less/common/**/*.less'],
    module: ['src/less/module/**/*.less'],
    moduleBase: 'src/less/module',
    baseWatch: ['src/less/_*.less']
  },
  js: {
    // 通用文件列表，会拼合到 app.js 中
    common: [
      'src/js/common/util.init.js',
      'src/js/common/app.init.js',
      'src/js/common/core.init.js',
      'src/js/common/data.init.js',
      'src/js/common/dict.init.js'
    ],
    // 开发用 js 文件夹
    // 页面内模块、独立类库、数据、工具方法、独立渲染器
    dev: [
      'src/js/module/**/*.js',
      'src/js/lib/**/*.js',
      'src/js/data/**/*.js',
      'src/js/util/**/*.js',
      'src/js/render/**/*.js'
    ],
    devBase: 'src/js'
  },
  img: ['src/images/**/*.*'],
  fonts: ['src/fonts/**/*.*'],
  vendor: ['src/vendor/**/*'],
  pug: {
    pages: ['src/pug/pages/**/*.pug', '!**/*/_*.pug'],
    pagesBase: 'src/pug/pages',
    views: ['src/pug/views/**/*.pug', '!**/*/_*.pug'],
    watch: ['src/pug/sect/**/*.pug', 'src/pug/layout/**/*.pug']
  }
};

// -----------
// LESS 处理
// -----------

// LESS 编译
function compileLess(input, base, output, watch, min, sourcemaps) {
  return gulp.src(input, {base: base})
    .pipe($.plumber())
    .pipe(watch ? $.watch(input, {base: base}) : noop())
    .pipe(watch || argv.using ? $.using({prefix: 'Using less'}) : noop())
    .pipe(sourcemaps ? $.sourcemaps.init() : noop())
    .pipe($.less())
    .pipe(min ? $.cleanCss() : noop())
    .pipe(sourcemaps ? $.sourcemaps.write() : noop())
    .pipe(gulp.dest(output));
}

// 定制 bootstrap
gulp.task('less:bootstrap', () => {
  return compileLess(src.less.bootstrap, '', getDistFolder('css'), false, !!argv.min, !!argv.sourcemaps);
});

// 监视 bootstrap
gulp.task('watch:bootstrap', () => {
  gulp.watch(src.less.bootstrapWatch, ['less:bootstrap']);
});

// 通用 app.css
gulp.task('less:common', () => {
  return compileLess(src.less.common, src.less.commonBase, getDistFolder('css'), false, !!argv.min, !!argv.sourcemaps);
});

// 监视 app.css
gulp.task('watch:less:common', () => {
  gulp.watch(src.less.commonWatch, ['less:common']);
});

// 常规样式文件
gulp.task('less:module', () => {
  return compileLess(src.less.module, src.less.moduleBase, getDistFolder('css'), !!argv.watch, !!argv.min, !!argv.sourcemaps);
});

gulp.task('watch:less:base', () => {
  $.watch(src.less.baseWatch, () => {
    compileLess(src.less.common, src.less.commonBase, getDistFolder('css'), false, !!argv.min, !!argv.sourcemaps);
    compileLess(src.less.module, src.less.moduleBase, getDistFolder('css'), false, !!argv.min, !!argv.sourcemaps);
  });
});

// LESS 任务集合
gulp.task('less', [
  'less:bootstrap',
  'less:common',
  'less:module'
]);

// -----------
// JS 处理
// -----------

// JS 复制
function copyJs(input, base, output, watch, min, sourcemaps) {
  return gulp.src(input, {base: base})
    .pipe($.plumber())
    .pipe(watch ? $.watch(input, {base: base}) : noop())
    .pipe(watch || !!argv.using ? $.using({prefix: 'Using js'}) : noop())
    .pipe(sourcemaps ? $.sourcemaps.init() : noop())
    .pipe(min ? $.uglify(uglifyOptions) : noop())
    .pipe(sourcemaps ? $.sourcemaps.write() : noop())
    .pipe(gulp.dest(output));
}

// 页面 JS 处理
gulp.task('js:dev', () => {
  return copyJs(src.js.dev, src.js.devBase, getDistFolder('js'), !!argv.watch, !!argv.min, !!argv.sourcemaps);
});

// 通用 JS 处理
gulp.task('js:common', () => {
  return gulp.src(src.js.common)
    .pipe($.plumber())
    .pipe(argv.using ? $.using({prefix: 'Using js'}) : noop())
    .pipe(argv.sourcemaps ? $.sourcemaps.init() : noop())
    .pipe($.concat('app.js'))
    .pipe(argv.min ? $.uglify(uglifyOptions) : noop())
    .pipe(argv.sourcemaps ? $.sourcemaps.write() : noop())
    .pipe(gulp.dest(getDistFolder('js')));
});

// 监视通用 JS
gulp.task('watch:js:common', () => {
  gulp.watch(src.js.common, ['js:common']);
});

gulp.task('js', [
  'js:dev',
  'js:common'
]);

// --------
// 拷贝区
// --------

// 复制文件
function copyFile(source, dest, watch) {
  return gulp.src(source)
    .pipe($.plumber())
    .pipe(watch ? $.watch(source) : noop())
    .pipe(argv.using ? $.using({prefix: 'Copying file'}) : noop())
    .pipe(gulp.dest(dest));
}

// 复制网站 icon 图标
gulp.task('icon', () => {
  gulp.src('src/favicon.ico')
    .pipe(gulp.dest(distFolder));
});

// 复制图片
gulp.task('img', () => {
  return copyFile(src.img, getDistFolder('images'), !!argv.watch);
});

// 复制定制 boostrap 用到的字体文件
gulp.task('fonts', () => {
  return copyFile(src.fonts, getDistFolder('fonts'), !!argv.watch);
});

// ----------------------
// 压缩图片
// 需安装 imagemin 插件
// ----------------------
gulp.task('min:img', () => {
  var imagemin = require('gulp-imagemin');
  return gulp.src(src.img)
    .pipe($.plumber())
    .pipe(argv.watch ? $.watch(src.img) : noop())
    .pipe(argv.using ? $.using({prefix: 'Minify images'}) : noop())
    .pipe(imagemin())
    .pipe(gulp.dest(getDistFolder('images')));
});

// 拷贝第三方资源和插件
gulp.task('vendor', () => {
  return gulp.src(src.vendor)
    .pipe($.plumber())
    .pipe(argv.watch ? $.watch(src.vendor) : noop())
    .pipe(gulp.dest(distFolder + '/vendor'));
});

// 压缩第三方资源和插件
gulp.task('min:vendor', () => {
  var jsFilter = $.filter(['**/*.js', '!**/*.min.js'], {restore: true});
  var cssFilter = $.filter(['**/*.css', '!**/*.min.css'], {restore: true});
  return gulp.src(src.vendor)
    .pipe($.plumber())
    .pipe(argv.watch ? $.watch(src.vendor) : noop())
    .pipe(jsFilter)
    .pipe(argv.using ? $.using({prefix: 'Using vendor js'}) : noop())
    .pipe(argv.min ? $.uglify(uglifyOptions) : noop())
    .pipe(jsFilter.restore)
    .pipe(cssFilter)
    .pipe(argv.using ? $.using({prefix: 'Using vendor css'}) : noop())
    .pipe(argv.min ? $.cleanCss() : noop())
    .pipe(cssFilter.restore)
    .pipe(gulp.dest(distFolder + '/vendor'));
});

// -----------------
// 处理页面静态文件
// PUG 格式
// -----------------

// 编译 PUG
function compilePug(input, base, output, watch, min) {
  return gulp.src(input, {base: base})
    .pipe($.plumber())
    .pipe(watch ? $.watch(input, {base: base}) : noop())
    .pipe(watch || argv.using ? $.using({prefix: 'Using pug'}) : noop())
    .pipe($.pug({pretty: true}))
    .pipe(gulp.dest(output));
}

// 特殊页面的处理，直接置于根目录下
gulp.task('pug:pages', () => {
  return compilePug(src.pug.pages, src.pug.pagesBase, distFolder, !!argv.watch, !!argv.min);
});

// 常规页面文件
gulp.task('pug:views', () => {
  return compilePug(src.pug.views, '', getDistFolder('html'), !!argv.watch, !!argv.min);
});

// 处理跳转的根目录 index.html
gulp.task('pug:index', () => {
  return compilePug('src/pug/index.pug', '', distFolder, !!argv.watch, !!argv.min);
});

// 处理内置登录页
gulp.task('pug:login', () => {
  return compilePug('src/pug/login.pug', '', distFolder, !!argv.watch, !!argv.min);
});

// 监视通用 pug 文件
// sect 目录和 layout 目录
gulp.task('watch:pug', () => {
  gulp.watch(src.pug.watch, () => {
    compilePug(src.pug.pages, src.pug.pagesBase, getDistFolder('html'), false, !!argv.min);
    compilePug(src.pug.views, '', getDistFolder('html'), false, !!argv.min);
  });
});

// PUG 任务入口
gulp.task('pug', [
  'pug:pages',
  'pug:views',
  'pug:index',
  'pug:login'
]);

// ----------------
// 开发与生产相关
// ----------------

// 其他监视任务入口
gulp.task('watch', [
  'watch:config',
  'watch:bootstrap',
  'watch:less:common',
  'watch:less:base',
  'watch:js:common',
  'watch:pug'
]);

// 生成所有文件
gulp.task('build', [
  'less',
  'js',
  'pug',
  'img',
  'fonts',
  'vendor',
  'config'
]);

// 针对 vendor 进行压缩的生成任务
gulp.task('build.vendor', [
  'less',
  'js',
  'pug',
  'img',
  'fonts',
  'min:vendor',
  'config'
]);

// 开发任务
gulp.task('dev', () => {
  argv.watch = true; // 开发监视文件
  argv.min = false; // 开发不压缩文件

  // 生成文件
  gulp.start('build');

  // 监视其他文件
  gulp.start('watch');

  // 开发任务针对本地模拟 json 数据的处理
  copyFile('json/**/*.json', distFolder + '/json', true);

  // 运行本地网站
  gulp.start('server');
});

// 打包任务
gulp.task('pack', () => {
  // 先清理，再进行生成
  del(distFolder + '/**/*', {force: true}).then(() => {
    log('已清理发布文件夹：' + distFolder);

    // 定制参数
    argv.watch = false; // 打包不监视文件
    argv.using = false; // 打包不显示文件记录
    argv.sourcemaps = false; // 打包不使用 sourcemaps
    argv.min = true; // 打包时压缩文件
    argv.pack = true; // 用于生成请求 json 版本的 config.js

    // 执行生成
    if (argv.vendor) {
      gulp.start('build.vendor');
    } else {
      gulp.start('build');
    }

    // 图标也打个包进去
    gulp.start('icon');
  });
});

// 针对开发环境的文件生成
gulp.task('build:dev', () => {
  // 先清理，再进行生成
  del(distFolder + '/**/*', {force: true}).then(() => {
    log('已清理发布文件夹：' + distFolder);

    // 定制参数
    argv.watch = false; // 打包不监视文件
    argv.using = false; // 打包不显示文件记录
    argv.sourcemaps = false; // 打包不使用 sourcemaps
    argv.min = false; // 不进行文件压缩
    argv.pack = true; // 用于生成请求 json 版本的 config.js

    // 执行生成
    if (argv.vendor) {
      gulp.start('build.vendor');
    } else {
      gulp.start('build');
    }
  });
});

// 默认任务入口为开发任务
gulp.task('default', ['dev']);

// 展示 sourcemaps 的任务入口
gulp.task('sourcemaps', () => {
  argv.sourcemaps = true;
  gulp.start('default');
});

// 将 dist 目录打包成 dist.zip 压缩包
gulp.task('zip', () => {
  let curFileStat = fs.statSync(distFolder);
  let srcGlob = curFileStat.isDirectory() ? distFolder + '/**' : distFolder;
  require('./build/zip.js')(srcGlob, distFolder + '.zip');
});
